﻿
using System.Linq;
using System.Collections.Generic;
using System;

 
 

namespace TreeExtensions
{
    public interface ILinqTree<T>
    {
        IEnumerable<T> Children();

        T Parent { get; }
    }
  
    public static class TreeExtensions
    {
        /// <summary>
        /// Returns a collection of descendant elements.
        /// </summary>
	    public static IEnumerable<System.Windows.DependencyObject> Descendants(this System.Windows.DependencyObject item)
        {
            ILinqTree<System.Windows.DependencyObject> adapter = new LinqToVisualTree.VisualTreeAdapter(item);
            foreach (var child in adapter.Children())
            {
                yield return child;

                foreach (var grandChild in child.Descendants())
                {
                    yield return grandChild;
                }
            }
        }    
           
        /// <summary>
        /// Returns a collection containing this element and all descendant elements.
        /// </summary>
	    public static IEnumerable<System.Windows.DependencyObject> DescendantsAndSelf(this System.Windows.DependencyObject item)
        {            
            yield return item;

            foreach (var child in item.Descendants())
            {
                yield return child;
            }
        }
        
        /// <summary>
        /// Returns a collection of ancestor elements.
        /// </summary>
	    public static IEnumerable<System.Windows.DependencyObject> Ancestors(this System.Windows.DependencyObject item)
        {
            ILinqTree<System.Windows.DependencyObject> adapter = new LinqToVisualTree.VisualTreeAdapter(item);
            
            var parent = adapter.Parent;
            while(parent != null)
            {
                yield return parent;
                adapter = new LinqToVisualTree.VisualTreeAdapter(parent);
                parent = adapter.Parent;
            }
        } 
        
        /// <summary>
        /// Returns a collection containing this element and all ancestor elements.
        /// </summary>
	    public static IEnumerable<System.Windows.DependencyObject> AncestorsAndSelf(this System.Windows.DependencyObject item)
        {
            yield return item;

            foreach (var ancestor in item.Ancestors())
            {
                yield return ancestor;
            }
        }
        
        /// <summary>
        /// Returns a collection of child elements.
        /// </summary>
	    public static IEnumerable<System.Windows.DependencyObject> Elements(this System.Windows.DependencyObject item)
        {
            ILinqTree<System.Windows.DependencyObject> adapter = new LinqToVisualTree.VisualTreeAdapter(item);
            foreach (var child in adapter.Children())
            {
                yield return child;                
            }
        }
        
        /// <summary>
        /// Returns a collection containing this element and all child elements.
        /// </summary>
	    public static IEnumerable<System.Windows.DependencyObject> ElementsAndSelf(this System.Windows.DependencyObject item)
        {
            yield return item;

            foreach (var child in item.Elements())
            {
                yield return child;
            }
        }
        
        /// <summary>
        /// Returns a collection of descendant elements which match the given type.
        /// </summary>
	    public static IEnumerable<T> Descendants<T>(this System.Windows.DependencyObject item)
        {
            return item.Descendants().Where(i => i is T).Cast<T>();
        }
        
        /// <summary>
        /// Returns a collection containing this element and all descendant elements.
        /// which match the given type.
        /// </summary>
	    public static IEnumerable<T> DescendantsAndSelf<T>(this System.Windows.DependencyObject item)
        {
            return item.DescendantsAndSelf().Where(i => i is T).Cast<T>();
        }
        
        /// <summary>
        /// Returns a collection of ancestor elements which match the given type.
        /// </summary>
	    public static IEnumerable<T> Ancestors<T>(this System.Windows.DependencyObject item)
        {
            return item.Ancestors().Where(i => i is T).Cast<T>();
        }
        
        /// <summary>
        /// Returns a collection containing this element and all ancestor elements.
        /// which match the given type.
        /// </summary>
	    public static IEnumerable<T> AncestorsAndSelf<T>(this System.Windows.DependencyObject item)
        {
            return item.AncestorsAndSelf().Where(i => i is T).Cast<T>();
        }
        
        /// <summary>
        /// Returns a collection of child elements which match the given type.
        /// </summary>
	    public static IEnumerable<T> Elements<T>(this System.Windows.DependencyObject item)
        {
            return item.Elements().Where(i => i is T).Cast<T>();
        }
        
        /// <summary>
        /// Returns a collection containing this element and all child elements.
        /// which match the given type.
        /// </summary>
	    public static IEnumerable<T> ElementsAndSelf<T>(this System.Windows.DependencyObject item)
        {
            return item.ElementsAndSelf().Where(i => i is T).Cast<T>();
        }
    }
    
    public static class EnumerableTreeExtensions
    {
        public static IEnumerable<System.Windows.DependencyObject> DrillDown(this IEnumerable<System.Windows.DependencyObject> items,
            Func<System.Windows.DependencyObject, IEnumerable<System.Windows.DependencyObject>> function)
        {
            foreach(var item in items)
            {
                foreach(var itemChild in function(item))
                {
                    yield return itemChild;
                }
            }
        }
        
        public static IEnumerable<T> DrillDown<T>(this IEnumerable<System.Windows.DependencyObject> items,
            Func<System.Windows.DependencyObject, IEnumerable<System.Windows.DependencyObject>> function)
            where T : System.Windows.DependencyObject
        {
            foreach(var item in items)
            {
                foreach(var itemChild in function(item))
                {
                    if (itemChild is T)
                    {
                        yield return (T)itemChild;
                    }
                }
            }
        }
    
        /// <summary>
        /// Returns a collection of descendant elements.
        /// </summary>
	    public static IEnumerable<System.Windows.DependencyObject> Descendants(this IEnumerable<System.Windows.DependencyObject> items)
        {
            return items.DrillDown(i => i.Descendants());
        }    
           
        /// <summary>
        /// Returns a collection containing this element and all descendant elements.
        /// </summary>
	    public static IEnumerable<System.Windows.DependencyObject> DescendantsAndSelf(this IEnumerable<System.Windows.DependencyObject> items)
        {            
            return items.DrillDown(i => i.DescendantsAndSelf());
        }
        
        /// <summary>
        /// Returns a collection of ancestor elements.
        /// </summary>
	    public static IEnumerable<System.Windows.DependencyObject> Ancestors(this IEnumerable<System.Windows.DependencyObject> items)
        {
            return items.DrillDown(i => i.Ancestors());
        } 
        
        /// <summary>
        /// Returns a collection containing this element and all ancestor elements.
        /// </summary>
	    public static IEnumerable<System.Windows.DependencyObject> AncestorsAndSelf(this IEnumerable<System.Windows.DependencyObject> items)
        {
            return items.DrillDown(i => i.AncestorsAndSelf());
        }
        
        /// <summary>
        /// Returns a collection of child elements.
        /// </summary>
	    public static IEnumerable<System.Windows.DependencyObject> Elements(this IEnumerable<System.Windows.DependencyObject> items)
        {
            return items.DrillDown(i => i.Elements());
        }
        
        /// <summary>
        /// Returns a collection containing this element and all child elements.
        /// </summary>
	    public static IEnumerable<System.Windows.DependencyObject> ElementsAndSelf(this IEnumerable<System.Windows.DependencyObject> items)
        {
            return items.DrillDown(i => i.ElementsAndSelf());
        }
        
        /// <summary>
        /// Returns a collection of descendant elements which match the given type.
        /// </summary>
	    public static IEnumerable<T> Descendants<T>(this IEnumerable<System.Windows.DependencyObject> items)
	        where T : System.Windows.DependencyObject
        {
            return items.DrillDown<T>(i => i.Descendants());
        }
        
        /// <summary>
        /// Returns a collection containing this element and all descendant elements.
        /// which match the given type.
        /// </summary>
	    public static IEnumerable<T> DescendantsAndSelf<T>(this IEnumerable<System.Windows.DependencyObject> items)
	        where T : System.Windows.DependencyObject
        {
            return items.DrillDown<T>(i => i.DescendantsAndSelf());
        }
        
        /// <summary>
        /// Returns a collection of ancestor elements which match the given type.
        /// </summary>
	    public static IEnumerable<T> Ancestors<T>(this IEnumerable<System.Windows.DependencyObject> items)
	        where T : System.Windows.DependencyObject
        {
            return items.DrillDown<T>(i => i.Ancestors());
        }
        
        /// <summary>
        /// Returns a collection containing this element and all ancestor elements.
        /// which match the given type.
        /// </summary>
	    public static IEnumerable<T> AncestorsAndSelf<T>(this IEnumerable<System.Windows.DependencyObject> items)
	        where T : System.Windows.DependencyObject
        {
            return items.DrillDown<T>(i => i.AncestorsAndSelf());
        }
        
        /// <summary>
        /// Returns a collection of child elements which match the given type.
        /// </summary>
	    public static IEnumerable<T> Elements<T>(this IEnumerable<System.Windows.DependencyObject> items)
	        where T : System.Windows.DependencyObject
        {
            return items.DrillDown<T>(i => i.Elements());
        }
        
        /// <summary>
        /// Returns a collection containing this element and all child elements.
        /// which match the given type.
        /// </summary>
	    public static IEnumerable<T> ElementsAndSelf<T>(this IEnumerable<System.Windows.DependencyObject> items)
	        where T : System.Windows.DependencyObject
        {
            return items.DrillDown<T>(i => i.ElementsAndSelf());
        }
    }
}